﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Nature.Text
{
    /// <summary>
    /// Abstract base class defining Text Fragment source, boundaries and common utilities
    /// </summary>
    [Serializable]
    public class TextFragment : IComparable<TextFragment>, IComparable
    {
        /// <summary>
        /// Create a new instance of the TextFragmentBase class covering 100% of the specified text source area
        /// </summary>
        public TextFragment(TextSource source)
        {
            Source = source;
            Index = 0;
            Length = source.OriginalText.Length;
        }

        /// <summary>
        /// Creates a new instance of the TextFragmentBase class
        /// </summary>
        /// <param name="source">text source containing the fragment</param>
        /// <param name="index">fragment index (position)</param>
        /// <param name="length">fragment length</param>
        public TextFragment(TextSource source, int index, int length)
        {
            Source = source;
            Index = index;
            Length = length;
        }

        /// <summary>
        /// Creates a new instance of the TextFragment class
        /// </summary>
        /// <param name="source">text source containing the fragment</param>
        /// <param name="capture">RegularExpressions Capture object representing the fragments index (position) and length</param>
        public TextFragment(TextSource source, Capture capture)
            : this(source, capture.Index, capture.Length) { }

        /// <summary>
        /// Text Source containing this fragment 
        /// </summary>
        public TextSource Source { get; private set; }

        /// <summary>
        /// Fragments index (position) in the Text Source 
        /// </summary>
        public int Index { get; private set; }

        /// <summary>
        /// Length of this fragmnet (number of characters)
        /// </summary>
        public int Length { get; private set; }

        /// <summary>
        /// End index of this fragment (the next position after the last character)
        /// </summary>
        public int EndIndex
        {
            get
            {
                return Index + Length;
            }
        }

        /// <summary>
        /// Original content of this fragment
        /// </summary>
        public string OriginalText
        {
            get
            {
                return Source.OriginalText.Substring(Index, Length);
            }
        }

        /// <summary>
        /// Adapted content of this fragment (for simplified parsing)
        /// </summary>
        public string AdaptedText
        {
            get
            {
                return Source.AdaptedText.Substring(Index, Length);
            }
        }

        public TextSource.PositionView this[int relativeOffset]
        {
            get
            {
                return Source[Index + relativeOffset];
            }
        }

        public TextSource.PositionView ToPositionView()
        {
            return Source[Index];
        }

        /// <summary>
        /// Returnes the first line of this text fragment, where all characters before the fragments 
        /// position are replaces with the given filler character
        /// </summary>        
        public string ToString(char filler)
        {
            return Source[Index].ToString(filler);
        }

        /// <summary>
        /// Returnes the first line of this text fragment underligned with a string filled with the
        /// given filler character. The fragments first position is underligned with the given pointer
        /// character
        /// </summary>   
        public string ToString(char filler, char pointer)
        {
            return Source[Index].ToString(filler, pointer);
        }

        public string ToString(bool original)
        {
            return original ? OriginalText.Substring(Index, Length) : AdaptedText.Substring(Index, Length);
        }

        public override int GetHashCode()
        {
            return OriginalText.GetHashCode();
        }

        public override string ToString()
        {
            return OriginalText;
        }

        public override bool Equals(object obj)
        {
            TextFragment other = obj as TextFragment;
            if (other != null)
            {
                return
                    Source == other.Source &&
                    Index == other.Index &&
                    Length == other.Length;
            }
            return false;
        }


        public bool IsChildOf(TextFragment other)
        {
            return
                Source == other.Source &&
                Index >= other.Index &&
                EndIndex <= other.EndIndex;
        }

        #region IComparable<TextFragmentBase> Members

        public int CompareTo(TextFragment other)
        {
            return Index.CompareTo(other.Index);
        }

        #endregion

        #region IComparable Members

        public int CompareTo(object obj)
        {
            if (obj is TextFragment)
            {
                return Index.CompareTo(((TextFragment)obj).Index);
            }
            throw new System.InvalidOperationException();
        }

        #endregion
    }
}
